package com.quectel.cms.controller.datav;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.func.LambdaUtil;
import com.quectel.business.common.util.sys.SysCodeUtils;
import com.quectel.cms.controller.BaseController;
import com.quectel.cms.util.SessionHolder;
import com.quectel.cms.vo.datav.PartyBuildingNoticeVo;
import com.quectel.cms.vo.datav.PartyBuildingStatisticsVo;
import com.quectel.cms.vo.datav.PartyPersonStatisticsVo;
import com.quectel.cms.vo.home.OrganizationPersonCountVo;
import com.quectel.cms.vo.home.PartyBuildingMeetingStaticsVo;
import com.quectel.cms.vo.home.WorkOrderCountVo;
import com.quectel.constant.core.partybuilding.PartyBuildingConstants;
import com.quectel.constant.core.partybuilding.PartyPersonConstants;
import com.quectel.constant.core.partybuildingnotice.PartyBuildingNoticeConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.constant.global.TreeData;
import com.quectel.constant.sys.SysCodeKeyConstants;
import com.quectel.core.module.partybuilding.dto.PartyOrganizationDto;
import com.quectel.core.module.partybuilding.dto.PartyPersonDto;
import com.quectel.core.module.partybuilding.service.PartyOrganizationService;
import com.quectel.core.module.partybuilding.service.PartyPersonService;
import com.quectel.core.module.partybuildingmeeting.dto.PartyBuildingMeetingDto;
import com.quectel.core.module.partybuildingmeeting.service.PartyBuildingMeetingService;
import com.quectel.core.module.partybuildingnotice.dto.PartyBuildingNoticeDto;
import com.quectel.core.module.partybuildingnotice.service.PartyBuildingNoticeService;
import com.quectel.sys.module.sys.dto.SysCodeDto;
import com.quectel.util.common.CopyUtils;
import com.quectel.util.common.Page;
import com.quectel.util.common.Request;
import com.quectel.util.common.Response;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDate;
import java.time.Period;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author yubobo
 * @email bobo.yu@quectel.com
 * @date 2022/1/10 下午2:17
 */
@RestController
@RequestMapping("datav/partyBuilding")
@Tag(name = "DataVPartyBuildingController", description = "大屏-智慧党建相关接口")
public class DataVPartyBuildingController extends BaseController {

    public static final Byte RNAGE_UNUSE = -1;
    public static final Byte RANGE_ONE=1;
    public static final Byte RANGE_TWO = 2;
    public static final Byte RANGE_THREE =3;
    public static final Byte RANGE_FOUR = 4;
    public static final Byte RANGE_FIVE = 5;

    @DubboReference
    private PartyBuildingNoticeService noticeService;
    @DubboReference
    private PartyPersonService partyPersonService;
    @DubboReference
    private PartyOrganizationService partyOrganizationService;
    @DubboReference
    private PartyBuildingMeetingService meetingService;

    /**
     * 党龄分布
     * 3年以下
     * 3-5年
     * 6-10年
     * 10年以上
     */
    @GetMapping("partyYearStatistics")
    @Operation(summary = "党员党龄分组- type:1(3年以下) 2(3-5年) 3(6-10年) 4(10年以上)")
    public Response<List<OrganizationPersonCountVo>> partyYearStatistics(
            @Parameter(description = "组织id") @RequestParam(required = true) Long partyId,
            @Parameter(description = "是否包含下级 0不包含 1包含") @RequestParam(required = false) Byte isInclude){
        Request request = Request.configParamsNotPage(Request.parseParams(httpServletRequest));
        super.fillAuthorityData(request.getParams());

        // 包含下级
        if (SystemConstants.YES.equals(isInclude)){
            List<PartyOrganizationDto> recursion = partyOrganizationService.recursion(partyId);
            request.getParams().put(PartyBuildingConstants.PARTY_ID_COLLECTION_FLAG, recursion.stream().map(PartyOrganizationDto::getId).toArray(Long[]::new));
            request.getParams().remove(LambdaUtil.getFieldName(PartyPersonDto::getPartyId));
        }

        List<PartyPersonDto> partyPersonDtoList = partyPersonService.queryList(request.getParams());

        Map<Byte, Integer> ageRangeCountMap = partyPersonDtoList.stream()
                .filter(partyPersonDto -> partyPersonDto.getProbationTime() != null)
                .collect(Collectors.groupingBy(partyPersonDto -> calculateProbationTimeRange(partyPersonDto.getProbationTime()),
                        Collectors.collectingAndThen(Collectors.counting(), Long::intValue)));

        ageRangeCountMap.remove(RNAGE_UNUSE);
        ageRangeCountMap.merge(RANGE_ONE, 0, Integer::sum);
        ageRangeCountMap.merge(RANGE_TWO, 0, Integer::sum);
        ageRangeCountMap.merge(RANGE_THREE, 0, Integer::sum);
        ageRangeCountMap.merge(RANGE_FOUR, 0, Integer::sum);

        List<OrganizationPersonCountVo> organizationPersonCountVoList = ageRangeCountMap.entrySet().stream()
                .map(entry -> {
                    OrganizationPersonCountVo organizationPersonCountVo = new OrganizationPersonCountVo();
                    organizationPersonCountVo.setType(entry.getKey());
                    organizationPersonCountVo.setCount(entry.getValue());
                    return organizationPersonCountVo;
                })
                .collect(Collectors.toList());

        return Response.<List<OrganizationPersonCountVo>>ok().wrap(organizationPersonCountVoList);
    }

    @GetMapping("noticeList")
    @Operation(summary = "党务公开")
    public Response<Page<PartyBuildingNoticeVo>> noticeList(
            @Parameter(description = "组织id") @RequestParam(required = true) Long partyId,
            @Parameter(description = "从1开始的页码数") @RequestParam Integer pageNo,
            @Parameter(description = "每页多少条") @RequestParam Integer pageSize){

        Request request = Request.configParams(Request.parseParams(httpServletRequest));

        request.getParams().put(LambdaUtil.getFieldName(PartyBuildingNoticeDto::getCategory), PartyBuildingNoticeConstants.Category.NOTICE_ANNOUNCEMENT.getType());
        request.getParams().put(LambdaUtil.getFieldName(PartyBuildingNoticeDto::getPartyId), partyId);

        int totalCount = noticeService.queryTotal(request.getParams());
        List<PartyBuildingNoticeDto> list = null;
        List<PartyBuildingNoticeVo> resultList = null;

        if (totalCount > 0) {
            list = noticeService.queryList(request.getParams());
            resultList = CopyUtils.copyList(list, PartyBuildingNoticeVo.class);
        } else {
            list = new ArrayList<>();
        }
        Page<PartyBuildingNoticeVo> page = new Page<>(request.getPageNo(), request.getPageSize(), totalCount, resultList);
        return Response.<Page<PartyBuildingNoticeVo>>ok().wrap(page);
    }

    /**
     * 三会一课统计
     */
    @GetMapping("meetingStatistics")
    @Operation(summary = "三会一课统计")
    public Response<List<PartyBuildingMeetingStaticsVo>> eduStatics(
            @Parameter(description = "组织id") @RequestParam(required = true) Long partyId,
            @Parameter(description = "是否包含下级 0不包含 1包含") @RequestParam(required = false) Byte isInclude) {
        Request request = Request.configParamsNotPage(Request.parseParams(httpServletRequest));
        super.fillAuthorityData(request.getParams());

        request.getParams().put(LambdaUtil.getFieldName(PartyBuildingMeetingDto::getPartyId),partyId);
        request.getParams().put(LambdaUtil.getFieldName(PartyBuildingMeetingDto::getCategory), SystemConstants.YES);

        List<SysCodeDto> categoryCodeList = SysCodeUtils.easyToGetByMark("ThreeOneLesson");
        List<PartyBuildingMeetingStaticsVo> eventList = new ArrayList<>();
        for (SysCodeDto sysCodeDto : categoryCodeList) {
            PartyBuildingMeetingStaticsVo pieInfo = new PartyBuildingMeetingStaticsVo();
            pieInfo.setName(sysCodeDto.getName());
            request.put(LambdaUtil.getFieldName(PartyBuildingMeetingDto::getType), sysCodeDto.getValue());

            request.put(SystemConstants.TIME_SLOT_KEY_PAIR.getLeft(), DateUtil.format(DateUtil.beginOfMonth(new Date()), DatePattern.NORM_DATETIME_PATTERN));
            request.put(SystemConstants.TIME_SLOT_KEY_PAIR.getRight(),DateUtil.format(DateUtil.endOfMonth(new Date()), DatePattern.NORM_DATETIME_PATTERN));
            int monthCount = meetingService.queryTotal(request.getParams());
            pieInfo.setThisMonth(monthCount);

            request.put(SystemConstants.TIME_SLOT_KEY_PAIR.getLeft(), DateUtil.format(DateUtil.beginOfYear(new Date()), DatePattern.NORM_DATETIME_PATTERN));
            request.put(SystemConstants.TIME_SLOT_KEY_PAIR.getRight(),DateUtil.format(DateUtil.endOfYear(new Date()), DatePattern.NORM_DATETIME_PATTERN));
            int yearCount = meetingService.queryTotal(request.getParams());
            pieInfo.setThisYear(yearCount);
            eventList.add(pieInfo);
        }
        return Response.<List<PartyBuildingMeetingStaticsVo>>ok().wrap(eventList);
    }

    /**
     * 学历分布
     */
    @GetMapping("eduStatistics")
    @Operation(summary = "学历分布")
    public Response<List<WorkOrderCountVo>> eduStatistics(
            @Parameter(description = "组织id") @RequestParam(required = true) Long partyId,
            @Parameter(description = "是否包含下级 0不包含 1包含") @RequestParam(required = false) Byte isInclude) {
        Request request = Request.configParamsNotPage(Request.parseParams(httpServletRequest));
        super.fillAuthorityData(request.getParams());

        // 包含下级
        if (SystemConstants.YES.equals(isInclude)){
            List<PartyOrganizationDto> recursion = partyOrganizationService.recursion(partyId);
            request.getParams().put(PartyBuildingConstants.PARTY_ID_COLLECTION_FLAG, recursion.stream().map(PartyOrganizationDto::getId).toArray(Long[]::new));
            request.getParams().remove(LambdaUtil.getFieldName(PartyPersonDto::getPartyId));
        }

        List<SysCodeDto> categoryCodeList = SysCodeUtils.easyToGetByMark(SysCodeKeyConstants.PARTY_PERSON_EDUCATION);
        List<WorkOrderCountVo> eventList = new ArrayList<>();
        for (SysCodeDto sysCodeDto : categoryCodeList) {
            WorkOrderCountVo pieInfo = new WorkOrderCountVo();
            pieInfo.setName(sysCodeDto.getName());
            request.put(LambdaUtil.getFieldName(PartyPersonDto::getEducation), sysCodeDto.getValue());
            int count = partyPersonService.queryTotal(request.getParams());
            pieInfo.setCount(count);
            eventList.add(pieInfo);
        }
        return Response.<List<WorkOrderCountVo>>ok().wrap(eventList);
    }



    /**
     * 党员年龄分布
     * 18-30岁
     * 31-40岁
     * 41-50岁
     * 51-60岁
     * 61岁以上
     */
    @GetMapping("partyPersonAgeStatistics")
    @Operation(summary = "党员年龄分组- type类型: 1(18-30岁) 2(31-40岁) 3(41-50岁) 4(51-60岁) 5(61岁以上)")
    public Response<List<OrganizationPersonCountVo>> partyPersonAgeStatistics(
            @Parameter(description = "组织id") @RequestParam(required = true) Long partyId,
            @Parameter(description = "是否包含下级 0不包含 1包含") @RequestParam(required = false) Byte isInclude){
        Request request = Request.configParamsNotPage(Request.parseParams(httpServletRequest));
        super.fillAuthorityData(request.getParams());

        // 包含下级
        if (SystemConstants.YES.equals(isInclude)){
            List<PartyOrganizationDto> recursion = partyOrganizationService.recursion(partyId);
            request.getParams().put(PartyBuildingConstants.PARTY_ID_COLLECTION_FLAG, recursion.stream().map(PartyOrganizationDto::getId).toArray(Long[]::new));
            request.getParams().remove(LambdaUtil.getFieldName(PartyPersonDto::getPartyId));
        }

        List<PartyPersonDto> partyPersonDtoList = partyPersonService.queryList(request.getParams());

        Map<Byte, Integer> ageRangeCountMap = partyPersonDtoList.stream()
                .filter(partyPersonDto -> partyPersonDto.getBirthDate() != null)
                .collect(Collectors.groupingBy(partyPersonDto -> calculateAgeRange(partyPersonDto.getBirthDate()), Collectors.collectingAndThen(Collectors.counting(), Long::intValue)));

        ageRangeCountMap.remove(RNAGE_UNUSE);
        ageRangeCountMap.merge(RANGE_ONE, 0, Integer::sum);
        ageRangeCountMap.merge(RANGE_TWO, 0, Integer::sum);
        ageRangeCountMap.merge(RANGE_THREE, 0, Integer::sum);
        ageRangeCountMap.merge(RANGE_FOUR, 0, Integer::sum);
        ageRangeCountMap.merge(RANGE_FIVE, 0, Integer::sum);

        List<OrganizationPersonCountVo> organizationPersonCountVoList = ageRangeCountMap.entrySet().stream()
                .map(entry -> {
                    OrganizationPersonCountVo organizationPersonCountVo = new OrganizationPersonCountVo();
                    organizationPersonCountVo.setType(entry.getKey());
                    organizationPersonCountVo.setCount(entry.getValue());
                    return organizationPersonCountVo;
                })
                .collect(Collectors.toList());

        return Response.<List<OrganizationPersonCountVo>>ok().wrap(organizationPersonCountVoList);
    }


    /**
     * 各党组织党员数量
     */
    @GetMapping("organizationPersonStatistics")
    @Operation(summary = "各党组织党员数量")
    public Response<List<OrganizationPersonCountVo>> organizationPersonStatistics(
            @Parameter(description = "组织id") @RequestParam(required = true) Long partyId,
            @Parameter(description = "是否包含下级 0不包含 1包含") @RequestParam(required = false) Byte isInclude){
        Request request = Request.configParamsNotPage(Request.parseParams(httpServletRequest));
        super.fillAuthorityData(request.getParams());

        List<OrganizationPersonCountVo> resultList = new ArrayList<>();
        List<PartyOrganizationDto> organizationList = partyOrganizationService.queryList(request.getParams());
        Map<String,Object> sqlMap = new HashMap<>();

        if (CollectionUtils.isNotEmpty(organizationList)){
            for (PartyOrganizationDto organizationDto : organizationList) {
                if (!organizationDto.getParentId().equals(SystemConstants.TREE_DEFAULT_PARENT_ID)){
                    sqlMap.put(LambdaUtil.getFieldName(PartyPersonDto::getPartyId), organizationDto.getId());
                    int queryTotal = partyPersonService.queryTotal(sqlMap);
                    OrganizationPersonCountVo addVo = new OrganizationPersonCountVo();
                    addVo.setName(organizationDto.getName());
                    addVo.setCount(queryTotal);
                    resultList.add(addVo);
                }
            }
        }

        return Response.<List<OrganizationPersonCountVo>>ok().wrap(resultList);
    }

    @GetMapping("partyBuildingStatistics")
    @Operation(summary = "党组织基础信息统计")
    public Response<PartyBuildingStatisticsVo> partyBuildingStatistics(
            @Parameter(description = "组织id") @RequestParam(required = true) Long partyId,
            @Parameter(description = "是否包含下级 0不包含 1包含") @RequestParam(required = false) Byte isInclude){

        Request request = Request.configParamsNotPage(Request.parseParams(httpServletRequest));
        super.fillAuthorityData(request.getParams());

        // 包含下级
        if (SystemConstants.YES.equals(isInclude)){
            List<PartyOrganizationDto> recursion = partyOrganizationService.recursion(partyId);
            request.getParams().put(PartyBuildingConstants.PARTY_ID_COLLECTION_FLAG, recursion.stream().map(PartyOrganizationDto::getId).toArray(Long[]::new));
            request.getParams().remove(LambdaUtil.getFieldName(PartyPersonDto::getPartyId));
        }

        int organizationCount = partyOrganizationService.queryTotal(request.getParams());

        // 正式
        request.put(LambdaUtil.getFieldName(PartyPersonDto::getPersonIdentity), PartyPersonConstants.PersonIdentityType.OFFICIAL.getType());
        int officialCount = partyPersonService.queryTotal(request.getParams());
        // 预备
        request.put(LambdaUtil.getFieldName(PartyPersonDto::getGender),  PartyPersonConstants.PersonIdentityType.PROBATIONARY.getType());
        int probationaryCount = partyPersonService.queryTotal(request.getParams());

        request.put(LambdaUtil.getFieldName(PartyPersonDto::getGender),  PartyPersonConstants.PersonIdentityType.NEWLY_DEVELOPED.getType());
        int newlyDevelopedCount = partyPersonService.queryTotal(request.getParams());

        request.getParams().remove(LambdaUtil.getFieldName(PartyPersonDto::getGender));
        PartyBuildingStatisticsVo vo = new PartyBuildingStatisticsVo();
        vo.setOfficialCount(officialCount);
        vo.setProbationaryCount(probationaryCount);
        vo.setNewlyDevelopedCount(newlyDevelopedCount);
        vo.setOrganizationCount(organizationCount);

        return Response.<PartyBuildingStatisticsVo>ok().wrap(vo);

    }


    /**
     * 党员统计
     * 男 女
     */
    @GetMapping("partyPersonStatistics")
    @Operation(summary = "党员统计")
    public Response<PartyPersonStatisticsVo> partyPersonStatistics(
            @Parameter(description = "组织id") @RequestParam(required = true) Long partyId,
            @Parameter(description = "是否包含下级 0不包含 1包含") @RequestParam(required = false) Byte isInclude) {

        Request request = Request.configParamsNotPage(Request.parseParams(httpServletRequest));
        super.fillAuthorityData(request.getParams());

        // 包含下级
        if (SystemConstants.YES.equals(isInclude)){
            List<PartyOrganizationDto> recursion = partyOrganizationService.recursion(partyId);
            request.getParams().put(PartyBuildingConstants.PARTY_ID_COLLECTION_FLAG, recursion.stream().map(PartyOrganizationDto::getId).toArray(Long[]::new));
            request.getParams().remove(LambdaUtil.getFieldName(PartyPersonDto::getPartyId));
        }

        int partyPersonCount = partyPersonService.queryTotal(request.getParams());

        // 男性
        request.put(LambdaUtil.getFieldName(PartyPersonDto::getGender), SystemConstants.MALE);
        int manCount = partyPersonService.queryTotal(request.getParams());
        // 女性
        request.put(LambdaUtil.getFieldName(PartyPersonDto::getGender), SystemConstants.FEMALE);
        int womanCount = partyPersonService.queryTotal(request.getParams());

        request.getParams().remove(LambdaUtil.getFieldName(PartyPersonDto::getGender));
        PartyPersonStatisticsVo vo = new PartyPersonStatisticsVo();
        vo.setPartyPersonCount(partyPersonCount);
        vo.setManCount(manCount);
        vo.setWomanCount(womanCount);
        return Response.<PartyPersonStatisticsVo>ok().wrap(vo);
    }


    /**
     * 党建信息发布
     * @return
     */
    @GetMapping("notice")
    @Operation(summary = "党建信息发布")
    public Response<PartyBuildingNoticeDto> notice(  @Parameter(description = "组织id") @RequestParam(required = true) Long partyId){
        Request request = Request.configParamsNotPage(Request.parseParams(httpServletRequest));

        request.getParams().put(LambdaUtil.getFieldName(PartyBuildingNoticeDto::getTenantId), SessionHolder.getSysUser().getTenantId());
        request.getParams().put(LambdaUtil.getFieldName(PartyBuildingNoticeDto::getPartyId), partyId);

        List<PartyBuildingNoticeDto> partyBuildingNoticeDtos = noticeService.queryList(request.getParams());
        if (CollectionUtils.isNotEmpty(partyBuildingNoticeDtos)){
            return Response.<PartyBuildingNoticeDto>ok().wrap(partyBuildingNoticeDtos.get(0));
        }else {
            return Response.<PartyBuildingNoticeDto>ok().wrap(null);
        }
    }

    /**
     * 列表
     */
    @GetMapping("treeData")
    @Operation(summary = "查询党组织树")
    public Response<List<TreeData>> treeData(
    ) {
        //查询列表数据
        Request request = Request.configParamsNotPage(Request.parseParams(httpServletRequest));
        super.fillAuthorityData(request.getParams());

        List<PartyOrganizationDto> depts = partyOrganizationService.queryList(request.getParams());

        List<TreeData> simpleTree = new ArrayList<>();

        simpleTree.addAll(
                depts.stream().map(v -> {
                    TreeData treeData = new TreeData();
                    treeData.setId(String.valueOf(v.getId()));
                    treeData.setName(v.getName());
                    treeData.setParentId(String.valueOf(v.getParentId()));
                    treeData.setOpen(SystemConstants.YES);
                    return treeData;
                }).collect(Collectors.toList())
        );
        if (simpleTree != null) {
            simpleTree.sort(new Comparator<TreeData>() {
                @Override
                public int compare(TreeData o1, TreeData o2) {
                    if (o1.getSort() != null && o2.getSort() != null) {
                        return o1.getSort() - o2.getSort();
                    }
                    return 0;
                }
            });
        }
        return Response.<List<TreeData>>ok().wrap(TreeData.simpleToChildren(simpleTree, SystemConstants.TREE_DEFAULT_PARENT_ID.toString()));
    }


    // 计算党员年龄范围
    private Byte calculateAgeRange(Date birthDate) {
        LocalDate currentDate = LocalDate.now();
        LocalDate probationDate = birthDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        Period period = Period.between(probationDate, currentDate);
        int age = period.getYears();

        if (age >= 18 && age <= 30) {
            return RANGE_ONE;
        } else if (age > 30 && age <= 40) {
            return RANGE_TWO;
        } else if (age > 40 && age <= 50) {
            return RANGE_THREE;
        } else if (age > 50 && age <= 60) {
            return RANGE_FOUR;
        } else if (age > 60){
            return RANGE_FIVE;
        }else {
            return RNAGE_UNUSE;
        }
    }

    // 计算党员党龄范围
    private Byte calculateProbationTimeRange(Date probationTime) {
        LocalDate currentDate = LocalDate.now();
        LocalDate probationDate = probationTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        Period period = Period.between(probationDate, currentDate);
        int years = period.getYears();

        if (years >= 0 && years < 3) {
            return RANGE_ONE;
        } else if (years >= 3 && years <= 5) {
            return RANGE_TWO;
        } else if (years > 5  && years <= 10) {
            return RANGE_THREE;
        } else if (years > 10) {
            return RANGE_FOUR;
        } else {
            return RNAGE_UNUSE;
        }
    }


}
